#include "Scene/ISceneManager.h"

#include "Graphics/IRenderEngine.h"
#include "Graphics/IRenderOperation.h"
#include "Graphics/IRenderable.h"
#include "Scene/IRenderQueue.h"
#include "Scene/IRenderQueueGroup.h"
#include "Scene/IRenderPriorityGroup.h"
#include "Scene/IRenderableCollection.h"
#include "Graphics/Pass.h"
#include "Geometry/CustomObject.h"
#include "Scene/SceneNode.h"


namespace tyro
{
	namespace Scene
	{

		


		

		void ISceneManager::RenderScene( Camera::Camera* camera, Graphics::IViewport* viewport )
		{
			activeViewport = viewport;
			activeCamera = camera;
			
			// Set the active viewport
			SetViewport(viewport);

			activeRenderEngine->SetAmbientLight(0.5f, 0.5f, 0.5f);

			// Find all visible objects in the scene
			if (updateVisibleObjects)
			{
				FindVisibleObjects(activeCamera); 
				updateVisibleObjects = false;
			}

			// Clear the frame
			if(activeViewport->GetClearEachFrame())
			{
				activeRenderEngine->ClearFrameBuffer(
				activeViewport->GetClearBuffers(),
				activeViewport->GetBackColour(),
				activeViewport->GetDepthClear() );

			}

			// Set the culling mode
			activeRenderEngine->SetCullingMode(CULL_CLOCKWISE);


			
			// Begin the frame
			activeRenderEngine->BeginFrame();
			
			// Set rasterization mode
			activeRenderEngine->SetPolygonMode(camera->GetPolygonMode());

			// Set the initial view and projection
			activeRenderEngine->SetProjectionMatrix(activeCamera->GetProjectionMatrixRS());

			activeViewMatrix = activeCamera->GetViewMatrix();

			if(cameraRelativeRendering)
			{
				activeViewMatrix.SetTranslation(Math::Vector3f::ZERO);
				cameraRelativePosition = activeCamera->GetTranslation();
			}

			SetViewMatrix(activeViewMatrix);


			// Render the scene
			RenderVisibleObjects();
			

			// End the frame
			activeRenderEngine->EndFrame();
		}

		void ISceneManager::SetActiveRenderEngine( Graphics::IRenderEngine* destRenderEngine )
		{
			activeRenderEngine = destRenderEngine;
		}

		Camera::Camera* ISceneManager::CreateCamera()
		{
			Camera::Camera *camera = new Camera::Camera(this);
			activeCamera = camera;
			return camera;
		}

		void ISceneManager::SetViewport( Graphics::IViewport* viewport )
		{
			activeViewport = viewport;
			activeRenderEngine->SetViewport(viewport);
			

		}

		void ISceneManager::SetViewMatrix( Math::Matrix4f viewMatrix )
		{
			activeRenderEngine->SetViewMatrix(viewMatrix);

		}


		void ISceneManager::RenderObject( Graphics::IRenderable* rend )
		{

			Graphics::IRenderOperation renderOp; 
			const_cast<Graphics::IRenderable*>(rend)->GetRenderOperation(renderOp);
			renderOp.renderableSrc = rend;


			
		
			// Get the number of world transforms
			USHORT_16 numMatrices = rend->GetNumWorldTransforms(); 


			// Get the world transform
			rend->GetWorldTransforms(tempMatrices);


			// Set the world transform
			if (numMatrices > 1)
			{
				activeRenderEngine->SetWorldMatrices(tempMatrices, numMatrices);
			}
			else
			{
				activeRenderEngine->SetWorldMatrix(*tempMatrices);
			}


			
			activeRenderEngine->SetColour(Graphics::Colour(tempMatrices[0].m03,tempMatrices[0].m13,tempMatrices[0].m23));
			activeRenderEngine->SetPolygonMode(PM_FILL);
			activeRenderEngine->RenderOperation(renderOp);
			activeRenderEngine->SetNormaliseNormals(false);
			/*activeRenderEngine->SetColour(Graphics::Colour::Green);
			activeRenderEngine->SetPolygonMode(PM_WIREFRAME);
			activeRenderEngine->RenderOperation(renderOp);*/



		}

		void ISceneManager::Init()
		{
			sceneRoot = 0;
			activerRenderQueue = 0;
			updateVisibleObjects = true;

		}

		SceneNode* ISceneManager::GetRootSceneNode( void )
		{
			if (!sceneRoot)
			{
				// Create root seen if not created
				sceneRoot = CreateRootSceneNodeImpl("Tyro/root");
			}
			return sceneRoot;
		}

		SceneNode* ISceneManager::CreateRootSceneNodeImpl( String name )
		{
			return new SceneNode(this, name);
		}

		void ISceneManager::UpdateSceneGraph( void )
		{
			GetRootSceneNode()->Update();
		}

		SceneNode* ISceneManager::CreateSceneNode( void )
		{
			SceneNode* child = CreateSceneNodeImpl();
			sceneNodeMap[child->GetName()] = child;
			return child;
		}

		SceneNode* ISceneManager::CreateSceneNode( const String& name )
		{
			SceneNode* child = CreateSceneNodeImpl(name);
			sceneNodeMap[child->GetName()] = child;
			return child;
		}

		SceneNode* ISceneManager::CreateSceneNodeImpl( void )
		{
			return new SceneNode(this);
		}

		SceneNode* ISceneManager::CreateSceneNodeImpl( const String& name )
		{
			return new SceneNode(this, name);
		}

		void ISceneManager::FindVisibleObjects( Camera::Camera* activeCamera )
		{
			// Get the active render que
			IRenderQueue* que = GetRenderQueue();

			bool includeChildren = true;

			// Add root scene node to render que
			GetRootSceneNode()->FindVisibleObjects(activeCamera, que, includeChildren);

		}

		IRenderQueue* ISceneManager::GetRenderQueue( void )
		{
			// Create render queue if needed 
			if (!activerRenderQueue)
			{
				InitialiseRenderQueue();
			}
			return activerRenderQueue;
		}

		void ISceneManager::InitialiseRenderQueue()
		{
			activerRenderQueue = new IRenderQueue();
		}

		void ISceneManager::RenderVisibleObjects( void )
		{
			IRenderQueue::RenderQueuedGroupMap* groupMap = GetRenderQueue()->GetQueuedGroupMap();
			IRenderQueue::RenderQueuedGroupMap::iterator i;

			for(i = groupMap->begin(); i != groupMap->end(); ++i)
			{
				RenderQueuedGroupObjects(i->second);
			}


		}

		void ISceneManager::RenderQueuedGroupObjects( IRenderQueueGroup* rendGroup )
		{
			// TODO Shadow passes

			// No shadows basic rendering pass
			RenderBasicQueuedGroupObjects(rendGroup);
		}

		void ISceneManager::RenderBasicQueuedGroupObjects( IRenderQueueGroup* rendGroup )
		{
			IRenderQueueGroup::PriorityGroupMap priorityMap = rendGroup->GetPriorityMap();
			IRenderQueueGroup::PriorityGroupMap::iterator i;

			for(i = priorityMap.begin(); i != priorityMap.end(); ++i)
			{
				IRenderPriorityGroup* priorityGroup = i->second;
				RenderObjects(priorityGroup->GetSolidBasic());
			}
		}

		void ISceneManager::RenderObjects( const IRenderableCollection& objs )
		{
			IRenderableCollection::RenderablePassList renderables = objs.GetRenderables();
			IRenderableCollection::RenderablePassList::iterator i;

			for (i = renderables.begin(); i != renderables.end(); ++i)
			{

				SetPass(i->pass);
				


				RenderObject(i->renderable);
			}
		}

		void ISceneManager::SetPass( Graphics::Pass* pass )
		{
			activeRenderEngine->SetSurfaceParams(
				pass->GetAmbient(), 
				pass->GetDiffuse(), 
				pass->GetSpecular(), 
				pass->GetEmmisive(), 
				pass->GetShininess());


			activeRenderEngine->SetLightingActive(true);
		}

		

	}
}

